package com.hu.network.http;

import android.content.Context;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import com.franmontiel.persistentcookiejar.PersistentCookieJar;
import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
import com.hu.network.http.cookie.CookiesManager;
import com.hu.network.http.exception.NetException;
import com.hu.network.http.trustmanager.AccetpAllTrustManager;
import com.hu.network.http.trustmanager.EmptyHostNameVerifier;
import okhttp3.CertificatePinner;
import okhttp3.ConnectionSpec;
import okhttp3.CookieJar;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;

/**
 * 说明：
 *
 * @author ： hucanhua
 * @date ： 2017/10/25
 */
public class HttpClient {
    private static HttpClient http = null;
    private OkHttpClient okHttpClient;
    private OkHttpClient okHttpsClient;

    private HttpClient() {
        this.okHttpClient = new OkHttpClient();
        this.okHttpsClient = new OkHttpClient();
    }

    private HttpClient(HttpClient.Builder builder) {
        this.okHttpClient = new OkHttpClient();
        this.okHttpsClient = new OkHttpClient();
        builder(builder);
    }

    private HttpClient builder(HttpClient.Builder builder) {
        OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
        OkHttpClient.Builder okHttpsBuilder = new OkHttpClient.Builder();
        if (builder.mCookieHandler != null) {
            okHttpBuilder.cookieJar(builder.mCookieHandler);
            okHttpsBuilder.cookieJar(builder.mCookieHandler);
        }

        if (builder.mConnectTimeout > 0L) {
            okHttpBuilder.connectTimeout(builder.mConnectTimeout, TimeUnit.SECONDS);
            okHttpsBuilder.connectTimeout(builder.mConnectTimeout, TimeUnit.SECONDS);
        }

        if (builder.mReadTimeout > 0L) {
            okHttpBuilder.readTimeout(builder.mReadTimeout, TimeUnit.SECONDS);
            okHttpsBuilder.readTimeout(builder.mReadTimeout, TimeUnit.SECONDS);
        }

        if (builder.mWriteTimeout > 0L) {
            okHttpBuilder.writeTimeout(builder.mWriteTimeout, TimeUnit.SECONDS);
            okHttpsBuilder.writeTimeout(builder.mWriteTimeout, TimeUnit.SECONDS);
        }

        if (builder.mCertificatePinner != null) {
            okHttpsBuilder.certificatePinner(builder.mCertificatePinner);
        }

        if (builder.mConnectionSpec != null) {
            okHttpsBuilder.connectionSpecs(Collections.singletonList(builder.mConnectionSpec));
        }

        if (builder.mSSLSocketFactory != null && builder.x509TrustManager != null) {
            okHttpsBuilder.sslSocketFactory(builder.mSSLSocketFactory, builder.x509TrustManager);
        }

        if (builder.mHostnameVerifier != null) {
            okHttpsBuilder.hostnameVerifier(builder.mHostnameVerifier);
        }
        okHttpBuilder.interceptors().addAll(builder.interceptors);
        okHttpsBuilder.interceptors().addAll(builder.interceptors);
        okHttpClient = okHttpBuilder.build();
        okHttpsClient = okHttpsBuilder.build();
        return this;
    }

    public static HttpClient getInstance() throws NetException {
        if (http == null) {
            throw new NetException("HTTP为NULL，请先初始化HTTP工具...", (new NullPointerException()).getCause());
        } else {
            return http;
        }
    }

    public OkHttpClient getHttp() throws NetException {
        if (this.okHttpClient == null) {
            throw new NetException("okHttpsClient is NULL,HTTP工具没有初始化...", (new NullPointerException()).getCause());
        } else {
            return this.okHttpClient;
        }
    }

    public OkHttpClient getHttps() throws NetException {
        if (this.okHttpsClient == null) {
            throw new NetException("okHttpsClient is NULL,HTTP工具没有初始化...", (new NullPointerException()).getCause());
        } else {
            return this.okHttpsClient;
        }
    }

    public static class Builder {
        private CookieJar mCookieHandler = null;
        private long mConnectTimeout = 15L;
        private long mReadTimeout = 120L;
        private long mWriteTimeout = 120L;
        private CertificatePinner mCertificatePinner = null;
        private ConnectionSpec mConnectionSpec = null;
        private SSLSocketFactory mSSLSocketFactory = null;
        private HostnameVerifier mHostnameVerifier = null;
        private List<Interceptor> interceptors = new ArrayList<>();
        private X509TrustManager x509TrustManager;

        public Builder() {
        }

        public HttpClient.Builder configConnectTimeout(long connectTimeout) {
            this.mConnectTimeout = connectTimeout;
            return this;
        }

        public HttpClient.Builder configReadTimeout(long readTimeout) {
            this.mReadTimeout = readTimeout;
            return this;
        }

        public HttpClient.Builder configWriteTimeout(long writeTimeout) {
            this.mWriteTimeout = writeTimeout;
            return this;
        }

        private HttpClient.Builder configServerTrusted(InputStream certificatesIns, InputStream keyStoreIns, String password) {
            SSLContext sslContext = this.sslContextForTrustedCertificates(certificatesIns, keyStoreIns, password.toCharArray());
            this.mSSLSocketFactory = sslContext.getSocketFactory();
            return this;
        }

        public HttpClient.Builder configCertificatePinner(CertificatePinner certificatePinner) {
            this.mCertificatePinner = certificatePinner;
            return this;
        }

        public HttpClient.Builder configTrustAll() {
            try {
                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(null, new TrustManager[]{new AccetpAllTrustManager()}, new SecureRandom());
                this.configHostnameVerifier(new EmptyHostNameVerifier());
                this.mSSLSocketFactory = sslContext.getSocketFactory();
                return this;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        public HttpClient.Builder configX509TrustManager(X509TrustManager x509TrustManager) {
            this.x509TrustManager = x509TrustManager;
            return this;
        }

        public HttpClient.Builder configHostnameVerifier(HostnameVerifier hostnameVerifier) {
            this.mHostnameVerifier = hostnameVerifier;
            return this;
        }

        public HttpClient.Builder configCookieAutoManager(Context context) {
            this.mCookieHandler =  new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));
            new CookiesManager(context);
            return this;
        }

        public HttpClient.Builder addInterceptor(Interceptor interceptor) {
            this.interceptors.add(interceptor);
            return this;
        }

        public HttpClient build() {
            HttpClient.http = new HttpClient(this);
            return HttpClient.http;
        }

        public SSLContext sslContextForTrustedCertificates(InputStream certificatesIns, InputStream keyStoreIns, char[] keyStorePassword) {
            try {
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                Collection certificates = certificateFactory.generateCertificates(certificatesIns);
                if (certificates.isEmpty()) {
                    throw new IllegalArgumentException("expected non-empty set of trusted certificates");
                } else {
                    KeyStore keyStore = this.newKeyStore(keyStoreIns, keyStorePassword);
                    int index = 0;

                    for (Object certificate : certificates) {
                        Certificate trustManagerFactory = (Certificate) certificate;
                        String sslContext = Integer.toString(index++);
                        keyStore.setCertificateEntry(sslContext, trustManagerFactory);
                    }

                    KeyManagerFactory managerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                    managerFactory.init(keyStore, keyStorePassword);
                    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    trustManagerFactory.init(keyStore);
                    SSLContext sslContext = SSLContext.getInstance("TLS");
                    sslContext.init(managerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
                    return sslContext;
                }
            } catch (GeneralSecurityException var11) {
                throw new RuntimeException(var11);
            }
        }

        private KeyStore newKeyStore(InputStream in, char[] password) throws GeneralSecurityException {
            try {
                KeyStore e = KeyStore.getInstance(KeyStore.getDefaultType());
                e.load(in, password);
                return e;
            } catch (IOException var4) {
                throw new RuntimeException(var4);
            }
        }
    }
}
